package com.bba.fms.common.ezspecial.service;

import com.alibaba.fastjson.JSON;
import com.bba.fms.common.exception.BusinessException;
import com.bba.fms.common.ezspecial.dto.CorrectData;
import com.bba.fms.common.ezspecial.dto.Edata;
import com.bba.fms.common.ezspecial.dto.ExcelResult;
import com.bba.fms.common.ezspecial.dto.FieldDto;
import com.bba.fms.common.ezspecial.model.EzSpecialPO;
import com.bba.fms.common.ezspecial.util.ConvertUtil;
import com.bba.fms.common.ezspecial.util.DtoUtil;
import com.bba.fms.common.ezspecial.util.PoiUtil;
import com.bba.fms.common.ezspecial.util.VerifyUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;

import java.lang.reflect.Field;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;

/**
 * @BelongsProject: fms
 * @Author: 王志鹏
 * @CreateTime: 2019-10-14 13:16
 * @description: 导入并校验, 返回经过标记
 */
@Slf4j
public class CoreServiceImpl implements CoreService {

    protected Workbook workbook;
    protected Sheet sheet;
    protected List<List<String>> data;
    protected Class cls;

    @Override
    public ExcelResult resolveExcelByXLSX(EzSpecialPO ezSpecialPO){

        initParams(ezSpecialPO);
        ExcelResult excelResult = new ExcelResult();

        List<FieldDto> fieldDtoList = null;
        for (int i = 0; i < data.size(); i++) {
            if (i == 0) {
                excelResult.setHeadList(DtoUtil.headList(data.get(i)));
                fieldDtoList = geFieldName(data.get(i));
                log.info("------------第一行处理结束--------------");
            } else {
                getExcelResult(excelResult, fieldDtoList, data.get(i), i);
            }
        }

        excelResult.setWorkbook(this.workbook);

        if (excelResult.getEdata() == null) {
            excelResult.setErrFlag(false);
        }else if (!excelResult.getEdata().isEmpty()){
            excelResult.setErrFlag(true);
        }
        return excelResult;
    }

    private ExcelResult getExcelResult(ExcelResult excelResult, List<FieldDto> fieldDtos, List<String> data, int row) {
        Object o = null;
        try {
            o = this.cls.newInstance();
        } catch (InstantiationException|IllegalAccessException e) {
            log.error(e.getMessage());
        }
        boolean flag = true; // 标记当前行是否出现过 错误

        for (int j = 0; j < data.size(); j++) {

            FieldDto festFileDto = fieldDtos.get(j);
            if (festFileDto == null) continue;
            String v = data.get(j);
            //开始校验
            boolean cellFlag = cheekedAndWriteERR(row, j, v, festFileDto);
            if (!cellFlag) flag = false;

            try {
                setEnetity(o, festFileDto.getColoumName(), v);
            } catch (Exception e) {
                log.info(e.getMessage());
            }
        }

        if (!flag) {
            Edata.addEdata(excelResult, data, row);
        } else {
            CorrectData.addCorrectData(excelResult, o, row);
        }
        return excelResult;
    }

    private List<FieldDto> geFieldName(List<String> data) {

        List<FieldDto> fileDtos = new ArrayList<>();

        for (String v : data) {
            fileDtos.add(ServiceUtil.getFiledByEzSpecialValue(this.cls, v));
        }

        return fileDtos;
    }

    private void initParams(EzSpecialPO ezSpecialPO) {
        this.workbook = ezSpecialPO.getWorkbook();
        this.sheet = ezSpecialPO.getWorkbook().getSheetAt(0);
        this.data = PoiUtil.readWorkbookBySheet(this.sheet);
        this.cls = ezSpecialPO.getCls();
    }

    private Boolean cheekedAndWriteERR(int row, int cell, String v, FieldDto festFileDto) {
        if (festFileDto == null) return false;
        boolean flag = startCheek(festFileDto, v);

        // write err
        if (!flag) {
            String msg = String.format("%s 不符合校验规则!", festFileDto.getColoumName());
            writeErrInWorkbook(this.workbook, row, cell, msg);
        }
        return flag;
    }

    private boolean startCheek(FieldDto festFileDto, String v) {

        boolean flag;
        boolean require = festFileDto.getRequire();
        String[] check = festFileDto.getCheck();
        String regular = festFileDto.getRegular();
        log.info("[" + v + "]:" + JSON.toJSONString(festFileDto) + (StringUtils.isEmpty(v) == !require));

        if (require) {//必填字段
            flag = StringUtils.isNotEmpty(v);
        } else {//不是必填字段
            flag = true;
            if (StringUtils.isNotEmpty(v)) {
                flag = cheekProcess(check, regular, v);
            }
        }

        return flag;
    }

    private boolean cheekProcess(String[] check, String regular, String v) {

        boolean b = true;
        if (check.length != 0 && regular != null) {
            throw new BusinessException("Ez Special ERR", "Cannot exist simultaneously check and regular");
        }

        if (check.length != 0 || regular != null) {
            if (check.length != 0) {
                b = VerifyUtil.cheekCustomize(check, v);
            } else {
                b = VerifyUtil.checkByRegular(regular, v);
            }
        }
        return b;
    }

    private void writeErrInWorkbook(Workbook workbook, int row, int cell, String msg) {
        PoiUtil.markWarningByCell(workbook, row, cell);
        PoiUtil.writeValueByRowLast(workbook, row, msg);
    }

    private static void setEnetity(Object o, String columnName, String v) throws NoSuchFieldException, ParseException, IllegalAccessException {
        Field field = o.getClass().getDeclaredField(columnName);
        field.setAccessible(true);
        Object val = null;
        if (StringUtils.isNotEmpty(v)) {
            val = ConvertUtil.tryToConvert(field.getGenericType(), v, columnName);
        }
        field.set(o, val);
    }

}